`include "PRV564Config.v"
`include "PRV564Define.v"
//////////////////////////////////////////////////////////////////////////////////////////////////
//  Date    : 2021                                                                              //
//  Author  : Jack.Pan                                                                          //
//  Desc    : Result Unit For PRV564 processor                                                  //
//  Version : 0.0(Orignal)                                                                      //
//////////////////////////////////////////////////////////////////////////////////////////////////
module ResultUnit
#(
    parameter UsedAsInstrFront = 1'b0       //default not used as instruction front
)
(
//---------------Global signal-----------
    input wire              RUi_CLK,
    input wire              RUi_ARST,
    input wire              RUi_Flush,
//--------------Result Queue output------
    input wire              RUi_RQ_V,
    input wire [7:0]        RUi_RQ_ID,
    input wire              RUi_RQ_WRERR,
    input wire              RUi_RQ_RDERR,
    input wire              RUi_RQ_RDY,
    input wire [127:0]      RUi_RQ_RDATA,
    output reg              RUo_RQ_ACK,
//---------------Access Table------------
    output reg              Tablei_RDEN,                //从Accesstable中读出一个表项
    output reg [7:0]        Tablei_RID,                 //从Accesstable中读出表项的ID
    output reg              Tablei_Remove,
    input wire              Tableo_V,                   //当前读出的表项有效
    input wire [`XLEN-1:0]  Tableo_ADDR,
    input wire [`XLEN-1:0]  Tableo_PC,
    input wire [7:0]        Tableo_ITAG,
    input wire [1:0]        Tableo_priv,
    input wire [7:0]        Tableo_opcode,
    input wire [1:0]        Tableo_opinfo,
    input wire [3:0]        Tableo_opsize,
    input wire              Tableo_ci,
    input wire              Tableo_InstPageFlt,
    input wire              Tableo_LoadPageFlt,
    input wire              Tableo_StorePageFlt,
    input wire              Tableo_InstAddrmis,
    input wire              Tableo_LoadAddrMis,
    input wire              Tableo_StoreAddrMis,
//----------------Result output---------------
    output reg              RUo_valid,
    output reg              RUo_InstPageFlt,
    output reg              RUo_InstAddrMis,
    output reg              RUo_InstAccFlt,
    output reg              RUo_LoadPageFlt,
    output reg              RUo_LoadAddrMis,
    output reg              RUo_LoadAccFlt,
    output reg              RUo_StorePageFlt,
    output reg              RUo_StoreAddrMis,
    output reg              RUo_StoreAccFlt,
    output reg              RUo_ci,
    output reg [7:0]        RUo_ITAG,
    output reg [1:0]        RUo_priv,
    output reg [`XLEN-1:0]  RUo_PC,
    output reg [`XLEN-1:0]  RUo_VADDR,
    output reg [`XLEN-1:0]  RUo_DATA,
    input wire              RUi_ready

);
    wire                OffADDR_sel;
    wire [`XLEN-1:0]    RDATA;                  //read data
    reg                 Result_ready;           //结果已经准备好
assign OffADDR_sel = UsedAsInstrFront;
//---------------产生Table读信号-------------------
always@(*)begin
    if(RUi_RQ_V)begin
        Tablei_RDEN = 1'b1;
        Tablei_RID  = RUi_RQ_ID;
    end
    else begin
        Tablei_RDEN = 1'b1;
        Tablei_RID  = RUi_RQ_ID;
    end
end
//----------------产生Table移除和RQACK信号----------------
always@(*)begin
    if(RUi_Flush)begin
        Tablei_Remove   = 1'b0;
        RUo_RQ_ACK      = 1'b0;
        Result_ready    = 1'b0;
    end
    else if(RUi_RQ_V)begin
        if(Tableo_V)begin   //当前项在表中有记录
            if(RUo_valid & !RUi_ready)begin
                Tablei_Remove   = 1'b0;
                RUo_RQ_ACK      = 1'b0;
                Result_ready    = 1'b0;
            end
            else begin
                Tablei_Remove   = 1'b1;
                RUo_RQ_ACK      = 1'b1;
                Result_ready    = 1'b1;
            end
        end
        else begin          //当前项在表中没有记录，直接舍弃
            Tablei_Remove   = 1'b0;
            RUo_RQ_ACK      = 1'b1;
            Result_ready    = 1'b0;
        end
    end
    else begin
        Tablei_Remove   = 1'b0;
        RUo_RQ_ACK      = 1'b0;
        Result_ready    = 1'b0;
    end
end
//------------------数据移位----------------------
DataShiftR          DataShiftR(
    .DATAi                  (RUi_RQ_RDATA),
    .Offset_ADDR            (OffADDR_sel ? Tableo_PC[3:0] :Tableo_ADDR[3:0]),
    .SIZEi                  (Tableo_opsize),
    .SIGNEXTi               ((Tableo_opinfo==`Sign32) | (Tableo_opinfo==`Sign64)),
    .DATAo                  (RDATA)
);
//---------------output registers---------------------
always@(posedge RUi_CLK or posedge RUi_ARST)begin
    if(RUi_ARST)begin
        RUo_valid           <= 1'b0;
        RUo_InstPageFlt     <= 1'b0;
        RUo_InstAddrMis     <= 1'b0;
        RUo_InstAccFlt      <= 1'b0;
        RUo_LoadPageFlt     <= 1'b0;
        RUo_LoadAddrMis     <= 1'b0;
        RUo_LoadAccFlt      <= 1'b0;
        RUo_StorePageFlt    <= 1'b0;
        RUo_StoreAddrMis    <= 1'b0;
        RUo_StoreAccFlt     <= 1'b0;
        RUo_ci              <= 1'b0;
        RUo_ITAG            <= 8'h00;
        RUo_priv            <= `Machine;
        RUo_PC              <= 'hx;
        RUo_VADDR           <= 'hx;
        RUo_DATA            <= 'hx;
    end
    else if(RUo_valid & !RUi_ready)begin
        RUo_valid           <= RUo_valid;
        RUo_InstPageFlt     <= RUo_InstPageFlt;
        RUo_InstAddrMis     <= RUo_InstAddrMis;
        RUo_InstAccFlt      <= RUo_InstAccFlt;
        RUo_LoadPageFlt     <= RUo_LoadPageFlt;
        RUo_LoadAddrMis     <= RUo_LoadAddrMis;
        RUo_LoadAccFlt      <= RUo_LoadAccFlt;
        RUo_StorePageFlt    <= RUo_StorePageFlt;
        RUo_StoreAddrMis    <= RUo_StoreAddrMis;
        RUo_StoreAccFlt     <= RUo_StoreAccFlt;
        RUo_ci              <= RUo_ci;
        RUo_ITAG            <= RUo_ITAG;
        RUo_priv            <= RUo_priv;
        RUo_PC              <= RUo_PC;
        RUo_VADDR           <= RUo_VADDR;
        RUo_DATA            <= RUo_DATA;
    end
    else begin
        RUo_valid           <= Result_ready;
        RUo_InstPageFlt     <= Tableo_InstPageFlt;
        RUo_InstAddrMis     <= Tableo_InstAddrmis;
        RUo_InstAccFlt      <= (Tableo_opcode==`LSU_eXecute) & RUi_RQ_RDERR;
        RUo_LoadPageFlt     <= Tableo_LoadPageFlt;
        RUo_LoadAddrMis     <= Tableo_LoadAddrMis;
        RUo_LoadAccFlt      <= RUi_RQ_RDERR;
        RUo_StorePageFlt    <= Tableo_StorePageFlt;
        RUo_StoreAddrMis    <= Tableo_StoreAddrMis;
        RUo_StoreAccFlt     <= RUi_RQ_WRERR;
        RUo_ci              <= Tableo_ci;
        RUo_ITAG            <= Tableo_ITAG;
        RUo_priv            <= Tableo_priv;
        RUo_PC              <= Tableo_PC;
        RUo_VADDR           <= Tableo_ADDR;
        RUo_DATA            <= RDATA;
    end
end

endmodule



//               128bit-64bit数据右对齐移位器，并可选的进行符号位拓展
module DataShiftR(
    input wire [127:0]  DATAi,
    input wire [3:0]    Offset_ADDR,
    input wire [3:0]    SIZEi,
    input wire          SIGNEXTi,       //进行符号位拓展
    output reg [63:0]   DATAo
);
    wire [63:0] shift0, shift1, shift2, shift3;

assign shift0 = Offset_ADDR[3] ? DATAi[127:64] : DATAi[63:0];       //高低64字节选择
assign shift1 = Offset_ADDR[2] ? {32'b0,shift0[63:32]} : shift0;    //高低32位选择
assign shift2 = Offset_ADDR[1] ? {48'b0,shift1[31:16]} : shift1;    //高低16位选择
assign shift3 = Offset_ADDR[0] ? {56'b0,shift2[15:8]} : shift2;     //高低8位选择
always@(*)begin
    if(SIGNEXTi)begin           //result need sign extension, higher bit filled by sign bit
        case(SIZEi)
            4'h1 : DATAo = {{56{shift3[7]}},shift3[7:0]};
            4'h2 : DATAo = {{48{shift3[15]}},shift3[15:0]};
            4'h4 : DATAo = {{32{shift3[31]}},shift3[31:0]};
            default: DATAo = shift3;
        endcase
    end
    else begin                  //result don't need sign extension, higher bit filled by 0
        case(SIZEi)
            4'h1 : DATAo = {56'b0,shift3[7:0]};
            4'h2 : DATAo = {48'b0,shift3[15:0]};
            4'h4 : DATAo = {32'b0,shift3[31:0]};
            default: DATAo = shift3;
        endcase
    end
end

endmodule

